﻿using System;
using System.ServiceModel;
using System.Threading;
using Needle.Bus.Engine.Utils;

namespace Needle.Bus.Engine.Stages
{
    public class Stage : EngineComponent, IStage
    {

        #region constructors

        /// <summary>
        /// Initializes a new instance of the StageBase class.
        /// </summary>
        public Stage(
            string id,
            IBufferQueue buffer,
            IStageFilter filter,
            IMessageHandler handler,
            IPerformanceCounter perfCounter)
            : this(new NamedMutex(id),
                id,
                buffer,
                filter,
                handler,
                perfCounter)
        { }

        /// <summary>
        /// Initializes a new instance of the StageBase class.
        /// </summary>
        public Stage(
            object mutex,
            string id,
            IBufferQueue buffer,
            IStageFilter filter,
            IMessageHandler handler,
            IPerformanceCounter perfCounter)
            : base(mutex, id)
        {
            if (buffer == null)
                throw new ArgumentNullException("buffer", "buffer is null.");
            if (filter == null)
                throw new ArgumentNullException("filter", "filter is null.");
            if (handler == null)
                throw new ArgumentNullException("handler", "handler is null.");
            if (perfCounter == null)
                throw new ArgumentNullException("perfCounter", "perfCounter is null.");

            Buffer = buffer;
            Filter = filter;
            Handler = handler;
            PerfCounter = perfCounter;
            BatchMode = new BatchModeOptions();
        }

        #endregion

        private BatchModeOptions _batchMode;
        public BatchModeOptions BatchMode
        {
            get
            {
                lock (ThisLock)
                {
                    return _batchMode;
                }
            }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("value");
                lock (ThisLock)
                {
                    _batchMode = value;
                }
            }
        }

        public IBufferQueue Buffer { get; private set; }

        public IStageFilter Filter { get; private set; }

        public IMessageHandler Handler { get; private set; }

        public IPerformanceCounter PerfCounter { get; private set; }

        private int _isActive;
        public bool IsActive
        {
            get { return _isActive == 1; }
        }

        public bool Activate()
        {
            if (State != CommunicationState.Opened)
                return false;
            return Interlocked.CompareExchange(ref _isActive, 1, 0) == 0;
        }

        public void Deactivate()
        {
            Interlocked.CompareExchange(ref _isActive, 0, 1);
        }

        #region privates

        protected override void OnOpen(TimeSpan timeout)
        {
            Buffer.Filter = Filter.Filter;
            PerfCounter.Open();
            Filter.Open();
            Buffer.Open();
            Handler.Initialize();
        }

        protected override void OnAbort()
        {
            Buffer.Abort();
            Filter.Abort();
            PerfCounter.Abort();
            Handler.Dispose();
        }

        protected override void OnClose(TimeSpan timeout)
        {
            Buffer.Close();
            Filter.Close();
            PerfCounter.Close();
            Handler.Dispose();
        }

        #endregion

    }
}
